package com.szjz.elasticsearch.eshelper.scaner;


import com.szjz.elasticsearch.eshelper.util.StringUtils;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author shibo
 * @desc es扫描器
 * @date 2020/6/3 周三
 */
public class ESScanner {

    private static Map<String, Class<?>> CLASSES = new HashMap<String, Class<?>>();
    /**
     * 类文件过滤器,只扫描一级类
     */
    private static FilenameFilter JAVA_CLASS_FILTER;
    /**
     * Java字节码文件后缀
     */
    private static final String CLASS_FILE_SUFFIX = ".class";
    private static String PACK_PREFIX;

    public ESScanner() {
        JAVA_CLASS_FILTER = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                // 排除内部内
                return !name.contains("$");
            }
        };
    }


    /**
     * @param packagePath 包路径
     * @param recursive   是否扫描子包
     * @return Integer 类数量
     * @Title: scanning
     * @Description 扫描指定包, Jar或本地
     */
    public static Integer scanning(String packagePath, boolean recursive) {
		CLASSES = new HashMap<String, Class<?>>();
        Enumeration<URL> dir;
        String filePackPath = packagePath.replace('.', '/');
        try {
            // 得到指定路径中所有的资源文件
            dir = Thread.currentThread().getContextClassLoader().getResources(filePackPath);
            PACK_PREFIX = Thread.currentThread().getContextClassLoader().getResource("").getPath();
            if (System.getProperty("file.separator").equals("\\")) {
                PACK_PREFIX = PACK_PREFIX.substring(1);
            }

            // 遍历资源文件
            while (dir.hasMoreElements()) {
                URL url = dir.nextElement();
                String protocol = url.getProtocol();

                if ("file".equals(protocol)) {
                    File file = new File(url.getPath());
                    scanFile(file);
                } else if ("jar".equals(protocol)) {
                    scanJar(url, recursive);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return CLASSES.size();
    }


    /**
     * @param dir Java包文件夹
     * @throws ClassNotFoundException
     * @Title: scan0
     * @Description 执行扫描
     */
    private static void scanFile(File dir) throws ClassNotFoundException {
        File[] fs = dir.listFiles(JAVA_CLASS_FILTER);
        for (int i = 0; fs != null && i < fs.length; i++) {
            File f = fs[i];
            String path = f.getAbsolutePath();

            // 跳过其他文件
            if (path.endsWith(CLASS_FILE_SUFFIX)) {
                String className = StringUtils.getPackageByPath(f, PACK_PREFIX); // 获取包名
                CLASSES.put(className, Class.forName(className));
            }
        }
    }

    /**
     * @param url       jar-url路径
     * @param recursive 是否递归遍历子包
     * @throws IOException
     * @throws ClassNotFoundException
     * @Title: scanJ
     * @Description 扫描Jar包下所有class
     */
    private static void scanJar(URL url, boolean recursive) throws IOException, ClassNotFoundException {
        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
        JarFile jarFile = jarURLConnection.getJarFile();

        // 遍历Jar包
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = (JarEntry) entries.nextElement();
            String fileName = jarEntry.getName();

            if (jarEntry.isDirectory()) {
                if (recursive) {
                }
                continue;
            }

            // .class
            if (fileName.endsWith(CLASS_FILE_SUFFIX)) {
                String className = fileName.substring(0, fileName.indexOf('.')).replace('/', '.');
                CLASSES.put(className, Class.forName(className));
            }

        }
    }

    /**
     * @return Map&lt;String,Class&lt;?&gt;&gt; K:类全名, V:Class字节码
     * @Title: getClasses
     * @Description 获取包中所有类
     */
    public static Map<String, Class<?>> getCLASSES() {
        return CLASSES;
    }

//    public static void main(String[] args) throws ClassNotFoundException{
//        ClassScanner cs = new ClassScanner();
//        int c = cs.scanning("W:/IWiFI/Code/trunk/operation/target/classes/", "com/cnp/andromeda/common/util/");
//        System.out.println(c);
//        System.out.println(cs.getClasses().keySet());
//
//        ClassScanner cs2 = new ClassScanner();
//        int c2 = cs2.scanning("com.cnp.swarm", false);
//        System.out.println(c2);
//        System.out.println(cs2.getClasses().keySet());
//    }


}
